﻿using System;
using System.Collections.Generic;
using System.Linq;
using Development.Tools;
using System.Reflection;
using Development.DataEntity;


namespace Development.DbData
{

    public class TableDataCache
    {
        public string TableName;
        public bool IsRank;
        public List<DataEntityBase> Datas = new List<DataEntityBase>();

    }
    /// <summary>
    /// 数据缓存区
    /// </summary>
    public class CacheFactory : Singleton<CacheFactory>,IDisposable
    {
        private Dictionary<string, TableDataCache> m_allDataCache = new Dictionary<string, TableDataCache>();
        private readonly int m_baseNo = 1000;
        private readonly object sync_root = new object();

        private readonly int m_InternalTime = 1000 * 60 * 5;  //五分钟更新一次排行榜
        private System.Timers.Timer m_timer = null;  //定时器
        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            var types = Assembly.GetEntryAssembly().GetTypes();
            var baseType = typeof(DataEntityBase);
            foreach (var ty in types)
            {
                if (ty.BaseType == baseType)
                {
                    DataEntityBase entity = Global.CreateObject(ty) as DataEntityBase;
                    string select = string.Format("select * from {0}", ty.Name);
                    DbProviderManager.Instance.ExecuteQuery(entity.GetDbName(), provider =>
                    {
                        TableDataCache table = new TableDataCache();
                        DbDataAttribute tableAttr = Attribute.GetCustomAttribute(ty, typeof(DbDataAttribute)) as DbDataAttribute;
                        table.IsRank = tableAttr.IsRank;
                        table.TableName = ty.Name;
                        while (provider.Read())
                        {
                            DataEntityBase obj = Global.CreateObject(ty) as DataEntityBase;
                            if (obj != null)
                            {
                                PropertyInfo[] props = obj.GetType().GetProperties();
                                foreach (PropertyInfo pi in props)
                                {
                                    DbDataAttribute atrr = Attribute.GetCustomAttribute(pi, typeof(DbDataAttribute)) as DbDataAttribute;
                                    if (atrr != null)
                                    {
                                        if (pi.PropertyType == typeof(Int32)
                                            || pi.PropertyType == typeof(float)
                                            || pi.PropertyType == typeof(string)
                                            || pi.PropertyType == typeof(long)
                                            || pi.PropertyType == typeof(Int64)
                                            || pi.PropertyType == typeof(UInt64)
                                            || pi.PropertyType == typeof(Boolean)
                                            || pi.PropertyType == typeof(Decimal)
                                            || pi.PropertyType == typeof(Double)
                                            || pi.PropertyType == typeof(UInt32)
                                            || pi.PropertyType == typeof(Single)
                                            || pi.PropertyType == typeof(Int16)
                                            || pi.PropertyType == typeof(UInt16)
                                            || pi.PropertyType == typeof(Byte)
                                            || pi.PropertyType == typeof(Byte[])
                                            || pi.PropertyType == typeof(Guid)
                                            )
                                        {
                                            object data = provider.Read(pi.Name);
                                            if (data == DBNull.Value)
                                            {
                                                data = pi.PropertyType.IsValueType ? Activator.CreateInstance(pi.PropertyType) : null;
                                            }
                                            if (pi.PropertyType == typeof(Single))
                                            {
                                                data = float.Parse(data.ToString());
                                            }
                                            pi.SetValue(obj, data, null);
                                        }
                                        else if (pi.PropertyType == typeof(DateTime))
                                        {
                                            object data = provider.Read(pi.Name);
                                            pi.SetValue(obj, DateTime.Parse(data.ToString()), null);
                                        }
                                        else
                                        {
                                            object data = provider.Read(pi.Name);
                                            if (data != DBNull.Value)
                                            {
                                                data = fastJSON.JSON.ToObject(provider.Read(pi.Name).ToString(), pi.PropertyType);
                                            }
                                            else
                                            {
                                                data = null;
                                            }
                                            pi.SetValue(obj, data, null);
                                        }
                                    }

                                }
                                table.Datas.Add(obj);

                            }
                        }
                        Log.WriteLog(ELogLevel.LOG_INFO, string.Format("load {0} finsh datacount = {1}", table.TableName, table.Datas.Count));
                        m_allDataCache.Add(ty.Name, table);
                    });
                }
            }
            m_timer_Elapsed(null, null);
            m_timer = new System.Timers.Timer(m_InternalTime);
            m_timer.Elapsed += m_timer_Elapsed;
            m_timer.Start();
        }


        void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            foreach (KeyValuePair<string, TableDataCache> r in m_allDataCache)
            {
                if (r.Value.IsRank && r.Value.Datas.Count != 0)
                {
                    List<DataEntityBase> list = null;
                    lock (sync_root)
                    {
                        r.Value.Datas.Sort();
                        list = r.Value.Datas.ToList();
                    }
                    for (int i = 0; i < list.Count; ++i)
                    {
                        DataEntityBase data = list[i];
                        data.ModifyLock < DataEntityBase>(p =>
                        {
                            // data.Rank = i + 1;
                        });
                    }
                }
            }
        }
        /// <summary>
        /// 返回null 说明
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public List<T> FindAll<T>(Predicate<T> match) where T : DataEntityBase
        {
            Type type = typeof(T);

            TableDataCache tableData = null;
            List<T> result = new List<T>();
            if (m_allDataCache.TryGetValue(type.Name, out tableData))
            {
                List<DataEntityBase> temp = null;
                lock (sync_root)
                {
                    temp = tableData.Datas.ToList();
                }
                foreach (T entity in temp)
                {
                    if (match(entity))
                    {
                        result.Add(entity);
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 找一个
        /// </summary>
        /// <param name="match"></param>
        /// <returns></returns>
        public T Find<T>(Predicate<T> match) where T : DataEntityBase
        {
            Type type = typeof(T);
            TableDataCache tableData = null;
            if (m_allDataCache.TryGetValue(type.Name, out tableData))
            {
                List<DataEntityBase> temp = null;
                lock (sync_root)
                {
                    temp = tableData.Datas.ToList();
                    foreach (T entity in temp)
                    {
                        if (entity != null && match(entity))
                        {
                            return entity;
                        }
                    }
                }
            }
            return null;
        }



        /// <summary>
        /// 增加数据
        /// </summary>
        /// <param name="key"></param>
        /// <param name="t"></param>
        public void AddDbData(DataEntityBase t)
        {
            Type type = t.GetType();
            TableDataCache tableData = null;
            if (this.m_allDataCache.TryGetValue(type.Name, out tableData))
            {
                lock (sync_root)
                {
                    tableData.Datas.Add(t);
                }
            }
            else
            {
                tableData = new TableDataCache();
                lock (sync_root)
                {
                    tableData.Datas.Add(t);
                }
                m_allDataCache.Add(type.Name, tableData);
            }
            //t.Insert();
        }

        /// <summary>
        /// 移除数据
        /// </summary>
        /// <param name="t"></param>
        public void Remove(DataEntityBase elem)
        {
            Type type = elem.GetType();
            TableDataCache tableData = null;
            if (this.m_allDataCache.TryGetValue(type.Name, out tableData))
            {
                lock (sync_root)
                {
                    tableData.Datas.Remove(elem);
                }
            }
            //  elem.Delete();
        }

        public int GetNextNo(string tableName)
        {
            if (m_allDataCache.ContainsKey(tableName))
            {
                lock (sync_root)
                {
                    return m_allDataCache[tableName].Datas.Count + m_baseNo;
                }
            }
            return m_baseNo;
        }

        // 摘要: 
        //     执行与释放或重置非托管资源相关的应用程序定义的任务。
        public void Dispose()
        {
            if(m_timer != null)
            {
                m_timer.Stop();
            }
        }


    }
}
